package com.micro.turtle.runner;

import cn.hutool.core.util.StrUtil;
import com.micro.turtle.constant.Cmd;
import com.micro.turtle.model.Conf;
import com.micro.turtle.model.Group;
import com.micro.turtle.model.Job;
import com.micro.turtle.model.Pipeline;
import com.micro.turtle.model.Project;
import java.util.ArrayDeque;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import lombok.SneakyThrows;

/**
 * 打Release包的自动化流程
 *
 * @author jason
 */
public class ReleaseRunner extends Runner {

    private final Conf conf;

    public ReleaseRunner(Conf conf) {
        super(Cmd.RELEASE);
        this.conf = conf;
    }

    @Override
    void exec() {

        // 1. 按顺序 查询 所有需要打 Release Jar 的组【 读 includeGroup 】
        List<Group> groups = GroupRunner.list();
        for (Group group : groups) {
            if (conf.getIncludeGroup().contains(group.getName())) {
                List<Project> projects = ProjectRunner.list(group.getId());
                // 2. 按顺序 查询 所有需要打 Release Jar 的项目， 然后排除不需要打包的项目【读 excludeProjects】
                for (Project project : projects) {
                    if (!conf.getExcludeProjects().contains(project.getName())) {
                        // 3. 按顺序 查询需要打包的项目, 下面最新的一条流水线【Pipeline】
                        List<Pipeline> pipelines = PipelineRunner.list(project.getId());
                        Pipeline pipeline = pipelines.get(0);
                        // 4. 运行 最新的一条流水线【Pipeline】中需要手动执行的 Stage 作业【Jobs】
                        // 同时查看是否发布到预发环境，
                        // 未发布发布到预发的话，跳过不打包。
                        // 已经发布到预发的话，直接运行名称为【Release】的Job(也就是Stage)
                        List<Job> jobs = JobRunner.list(pipeline.getProjectId(), pipeline.getId());
                        Map<String, Job> jobMap = jobs.stream().collect(Collectors.toMap(Job::getName, item -> item));

                        String next = "Build";
                        while (StrUtil.isNotBlank(next)){
                            Job job = jobMap.get(next);
                            if ("manual".equals(job.getStatus())) {
                                // 手动触发
                                JobRunner.play(pipeline.getProjectId(), job.getId());
                            }
                            // 轮询 等执行完完
                            loop(pipeline, job);
                            next = getNextWork(next);
                        }
                        // 5. 等待【Release】步骤执行完成，会产生一个新的流水线【Pipeline】,需要手动执行。
                        // 里面包含一个【PublishRlease】的Job, 这个Job是用来把原有gradle.properties的-SNAPSHOT版本，改为Release版本
                        Job publishRlease = findJob(pipeline);
                        // 6. 触发步骤5产生的流水线的任务
                        JobRunner.play(pipeline.getProjectId(), publishRlease.getId());
                    }
                }
            }
        }
    }


    static class JobWorker {

        Job job;
        Callable<Boolean> work;

        public JobWorker(Job job, Callable<Boolean> work) {
            this.job = job;
            this.work = work;
        }

        public Integer getId() {
            return job.getId();
        }
    }

    public String getNextWork(String name) {
        switch (name) {
            case "Build":
                return "BuildImage";
            case "BuildImage":
                return "DeployTest";
            case "DeployTest":
                return "DeployTest_All";
            case "DeployTest_All":
               return "DeployPre";
            case "DeployPre":
               return "DeployPre_All";
            case "DeployPre_All":
                return "Release";
            default:
        }
        return "";
    }

    @SneakyThrows
    private void loop(Pipeline pipeline, Job job) {
        while (true) {
            Job detail = JobRunner.detail(pipeline.getProjectId(), job.getId());
            if (!"success".equals(detail.getStatus())) {
                break;
            }
            TimeUnit.SECONDS.sleep(10);
        }
    }

    @SneakyThrows
    private Job findJob(Pipeline pipeline) {
        Job job = null;
        while (true) {
            List<Pipeline> pipelines = PipelineRunner.list(pipeline.getProjectId());
            // 找倒数第二条
            for (Pipeline newPipe : pipelines) {
                if (newPipe.getId() > pipeline.getId()){
                    job = publishRelease(newPipe);
                }
            }
            if (Objects.nonNull(job)){
                break;
            }
            TimeUnit.SECONDS.sleep(10);
        }
        return job;
    }

    private Job publishRelease(Pipeline pipeline){
        List<Job> jobs = JobRunner.list(pipeline.getProjectId(), pipeline.getId());
        return jobs.stream().filter(item -> "PublishRlease".equals(item.getName())).findAny().orElse(null);
    }

}
